--------------------------------------------------------------------------------
-- This package is a thick Ada binding to the GNU Multiple Precision Library.
-- See <http://gmplib.org/>.
--
-- Copyright (C) 2009 Vincent DIEMUNSCH.
-- GNU General Public License.
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU General Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your option) any later
-- version.
--
-- This file is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- this program.  If not, see <http://www.gnu.org/licenses/>.
----------------------------------------------------------------------------------
--
-- This package declares a new private type : Unbounded_Integer, that is an
-- abstraction of an Integer value of arbitrary size.

with Ada.Finalization;

package GMP.Integers is

   type Unbounded_Integer is private;
   -- Private type so that all the following functions are NOT primitive operations.

   function To_Unbounded_Integer (Value : Integer) return Unbounded_Integer;
   function To_Unbounded_Integer (Value : mpz_t)   return Unbounded_Integer;
   function To_Unbounded_Integer (Image : String)  return Unbounded_Integer;
   -- This function creates an Unbounded_Integer from a value given by a string
   -- that must conform to the Ada Standard for Integer literals (decimal
   -- literals and base literals), except the fact that the base can be above
   -- 16, but it must be under (or equal to) 62. (And in that case we use digits
   -- from 0 .. 9, A .. Z, a .. z).
   -- We tolerate a negative value (i.e. the '-' at the beginning), even if in
   -- Ada the '-' is seen as a unary operator and not part of the literal.
   -- Exemples :
   --      Decimal literals : 2  0  1E6 123_456
   --      Based literals   : 2#1111_1111#  16#FF#  016#0ff#  = 255
   --                         16#E#E1  2#1110_0000#           = 224
   Data_Error : Exception;

   subtype Base_Range is Integer range 2 .. 62;
   function Image (Object : Unbounded_Integer;
                   Base   : Base_Range := 10)   return String;
   -- This function return an integer literal (decimal literal or base literal)
   -- that conform to the Ada Standard except the '-' at the beginning and the
   -- fact that base can be any integer between 2 and 62.


   ----------------------------
   -- "Standard" description --
   ----------------------------

   -- (Mimics Standard package)
   -- The operators for type Integer are as follows:

   function "="  (Left, Right : Unbounded_Integer) return Boolean;
   function "<"  (Left, Right : Unbounded_Integer) return Boolean;
   function "<=" (Left, Right : Unbounded_Integer) return Boolean;
   function ">"  (Left, Right : Unbounded_Integer) return Boolean;
   function ">=" (Left, Right : Unbounded_Integer) return Boolean;
   pragma Inline ("=", "<", "<=", ">", ">=");

   function "+"   (Right : Unbounded_Integer) return Unbounded_Integer;
   function "-"   (Right : Unbounded_Integer) return Unbounded_Integer;
   function "abs" (Right : Unbounded_Integer) return Unbounded_Integer;
   pragma Inline ("+", "-", "abs");

   function "+"   (Left, Right : Unbounded_Integer) return Unbounded_Integer;
   function "-"   (Left, Right : Unbounded_Integer) return Unbounded_Integer;
   function "*"   (Left, Right : Unbounded_Integer) return Unbounded_Integer;
   function "/"   (Left, Right : Unbounded_Integer) return Unbounded_Integer;
   function "rem" (Left, Right : Unbounded_Integer) return Unbounded_Integer;
   function "mod" (Left, Right : Unbounded_Integer) return Unbounded_Integer;
   pragma Inline ("+", "-", "*", "/", "mod", "rem");

   function "**"  (Left : Unbounded_Integer; Right : Natural)
                   return Unbounded_Integer;

   ----------------------------
   -- with Standard Integers --
   ----------------------------

--     function "+" (Left : Unbounded_Integer; Right : Integer) return Unbounded_Integer;
--     function "-" (Left : Unbounded_Integer; Right : Integer) return Unbounded_Integer;
--     function "*" (Left : Unbounded_Integer; Right : Integer) return Unbounded_Integer;
--     function "/" (Left : Unbounded_Integer; Right : Integer) return Unbounded_Integer;
--     function "/" (Left : Integer; Right : Unbounded_Integer) return Unbounded_Integer;

   Procedure To_Standard_Integer(Item     : in  Unbounded_Integer;
                                 Target   : out Integer;
                                 Is_Valid : out Boolean);
   -- If the Value of the unbounded integer fits a standard integer, then
   -- Is_Valid is true and the Result is set to this value.
   -- Warning : we make the assumption that Integer and C.int are the same..
   --           this is always true for GNAT/GCC but not for all compilers !

   -------------------------
   -- with Standard Float --
   -------------------------

   function To_Long_Float (Value : Unbounded_Integer) return Long_Float;
   -- This function convert the Unbounded_Integer to a Long_Float, i.e. for GNAT
   -- a double in C. I know that strictly speaking it is not portable but will
   -- GMP be compiled outside GCC / GNAT ?

   --------------------------------
   -- Number Theoretic Functions -- 
   --------------------------------
   
   function GCD (A, B : Unbounded_Integer) return Unbounded_Integer;
   procedure Extended_GCD (A, B             :     Unbounded_Integer;
                           Coeff_A, Coeff_B : out Unbounded_Integer;
                           GCD              : out Unbounded_Integer);
   -- Return the greatest common divisor of A and B. The result is
   -- always positive even if one or both input operands are negative.
   -- In addition, set Coeff_A and Coeff_B to coefficients satisfying:
   --  * GCD = A*Coeff_A + B*Coeff_B  
   --  * |Coeff_A| ≤ |B| and |Coeff_B| ≤ |A|.

private

   type Unbounded_Integer is new Ada.Finalization.Controlled with record
      Value : mpz_t;
   end record;

   overriding procedure Initialize (Object: in out Unbounded_Integer);
   overriding procedure Adjust     (Object: in out Unbounded_Integer);
   overriding procedure Finalize   (Object: in out Unbounded_Integer);

end GMP.Integers;
